﻿#region Imported Libraries
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using org.webguvenligi.NSecureImageLib.GraphicFileFormats.PNG;
#endregion
using org.webguvenligi.NSecureImageLib.GraphicFileFormats.Utilities;
namespace NSecureImageTest
{
    [TestClass()]
    public class PNGParserTest
    {

        #region Static Helpers



        [TestMethod()]
        public void WholePngTesting()
        {
            string[] sampleFiles =
                System.IO.Directory.GetFiles(TestHelper.GetCurrentImagePath());
            foreach (string sampleFile in sampleFiles)
            {
                try
                {
                    using (PNGParser tempParser = new PNGParser(new FileStream(sampleFile,
                        FileMode.Open, FileAccess.Read)))
                    {
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("-----------------------------------");
                    Debug.WriteLine(sampleFile);
                    Debug.WriteLine(ex.Message);
                    Debug.WriteLine("-----------------------------------");
                    Debug.WriteLine(ex.StackTrace);
                    Debug.WriteLine("-----------------------------------");
                    if (ex.InnerException != null)
                        Debug.WriteLine(ex.InnerException.Message);
                    Debug.WriteLine("-----------------------------------");
                }
            }
        }

        public static List<PNGBaseChunk> GetChunksFromFile(string fileName)
        {
            return GetChunksFromFile(fileName, false);
        }
        [TestMethod()]
        [ExpectedException(typeof(InvalidDataException))]
        public void itxt_keyword_length()
        {
            object result = PNGParserTest.GetChunksFromFile("itxt_keyword_length.png");
        }
        [TestMethod()]
        public void TextOperations()
        {
            PNGParser tempParser = new PNGParser(new FileStream(TestHelper.GetCurrentImagePath() + "\\" + "analyzingcert.png", FileMode.Open, FileAccess.Read));
            List<PNGBaseChunk> textChunks = tempParser.ResultChunks.FindChunks<TextualChunk>().ToList();
            TextualChunk currentChunks;
            foreach (PNGBaseChunk currentChunk in textChunks)
            {
                currentChunks = currentChunk as TextualChunk;
                Debug.WriteLine(currentChunks.ToString());
            }
            TextualChunk simpleChunk = new TextualChunk()
            {
                Text = "Helloo test this heloo",
                Keyword = "Welcome World"
            };
            tempParser.Insert(simpleChunk);
            using (Stream sourceStream = new NonClosingMemoryStream())
            {
                tempParser.WriteImage(sourceStream, false);
                sourceStream.Position = 0;
                PNGParser tempPars = new PNGParser(sourceStream);
                textChunks = tempParser.ResultChunks.FindChunks<TextualChunk>().ToList();
                Assert.IsTrue(textChunks.Count == 2);
                TextualChunk currentChunk = textChunks[1] as TextualChunk;
                Assert.IsTrue(currentChunk.Text == simpleChunk.Text);
                Assert.IsTrue(currentChunk.Keyword == simpleChunk.Keyword);
            }
        }
        [TestMethod()]
        public void ITXTParsingTest()
        {
            PNGParser tempParser = new PNGParser(new FileStream(TestHelper.GetCurrentImagePath() + "\\" + "itxt_keyword_length_2.png", FileMode.Open, FileAccess.Read));
            int chunkIndex = 0;
            ITextualChunk currentChunk =
                tempParser.ResultChunks.FindChunk<ITextualChunk>(out chunkIndex);
            currentChunk.CompressionByte = 1;
            currentChunk.Text = "Hellooooooooooooooooooooooooooooooooooooooooooooooo";
            using (Stream sourceStream = new NonClosingMemoryStream())
            {
                tempParser.WriteImage(sourceStream, false);
                MemoryStream dataStream = new MemoryStream();
                sourceStream.Position = 0;
                sourceStream.CopyTo(dataStream);
                dataStream.Position = 0;
                PNGParser tempPars = new PNGParser(dataStream);
                currentChunk =
               tempParser.ResultChunks.FindChunk<ITextualChunk>(out chunkIndex);
                Assert.IsTrue(currentChunk.CompressionByte == 1);
                Assert.IsTrue(currentChunk.Text == "Hellooooooooooooooooooooooooooooooooooooooooooooooo");
                dataStream.Dispose();
            }
        }
        [TestMethod()]
        public void ITXTParsingAndWritingTest()
        {
            List<PNGBaseChunk> result = PNGParserTest.GetChunksFromFile("itxt_keyword_length_2.png");
        }
        /// <summary>
        /// Gets the chunks from file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="cleanChunks">if set to <c>true</c> [clean chunks].</param>
        /// <returns></returns>
        protected static List<PNGBaseChunk> GetChunksFromFile(string fileName, bool cleanChunks)
        {
            using (PNGParser tempParser = new PNGParser(new FileStream(TestHelper.GetCurrentImagePath() + "\\" + fileName, FileMode.Open, FileAccess.Read)))
            {
                if (cleanChunks)
                    tempParser.CleanAdditionalChunks();
                return tempParser.ResultChunks;
            }
        }

        private static IEnumerable<PNGBaseChunk> ChunkFinder(List<PNGBaseChunk> foundChunks,
                                                     string chunkType)
        {
            var textChunks = from p in foundChunks
                             where (p.ChunkTypeValue.ChunkTypeDescription == chunkType)
                             select p;
            Assert.IsNotNull(textChunks);
            return textChunks;
        }
        #endregion

        [TestMethod()]
        public void CheckUncompressedTextualData()
        {
            int counter = -1;
            var textChunks = ChunkFinder(GetChunksFromFile("glmda.png"), "tEXt");
            Assert.IsTrue(textChunks.Count() > 0, "No Text Chunk Found In File");
            foreach (var textChunk in textChunks)
            {
                Assert.IsTrue((textChunk as TextualChunk).Keyword == "Software");
                Assert.IsTrue((textChunk as TextualChunk).Text == "Paint.NET v3.31");
                counter += 1;
            }
            textChunks = ChunkFinder(GetChunksFromFile("glmda.png", true), "tEXt");
            Assert.IsTrue(textChunks.Count() == 0, "ZText Chunk Not Removed From File");
        }

        static Dictionary<string, List<PNGBaseChunk>> imageCache;

        static PNGParserTest()
        {
            imageCache = new Dictionary<string, List<PNGBaseChunk>>();
            imageCache.Add("analyzingcert.png", GetChunksFromFile("analyzingcert.png"));
        }



        [TestMethod()]
        public void CheckPalette()
        {
            List<PNGBaseChunk> targetFile =
                GetChunksFromFile("ps1n0g08.png");
        }
        //[TestMethod()]
        //public void itxt_keyword_length()
        //{
        //    GetChunksFromFile("itxt_keyword_length.png");
        //}
        [TestMethod()]
        [ExpectedException(typeof(org.webguvenligi.NSecureImageLib.GraphicFileFormats.PNG.Exceptions.PngInvalidDataException))]
        public void MultipleIHDR()
        {
            GetChunksFromFile("multiple_ihdr.png");
        }
        [TestMethod()]
        public void CheckHisto()
        {
            List<PNGBaseChunk> targetFile = GetChunksFromFile("ch1n3p04.png");
            HistogramChunk phsyChunk = ChunkFinder(targetFile, "hIST").SingleOrDefault() as HistogramChunk;
            Assert.IsNotNull(phsyChunk, "No hIST Chunk Found");
            Assert.IsTrue(phsyChunk.HistogramValues.Count == 15, "Invalid Histogram Values");

        }
        [TestMethod()]
        public void CheckHisto2()
        {
            List<PNGBaseChunk> targetFile =
                GetChunksFromFile("ch2n3p08.png");
            HistogramChunk phsyChunk = ChunkFinder(targetFile, "hIST").Single() as HistogramChunk;
            Assert.IsNotNull(phsyChunk, "No hIST Chunk Found");
            Assert.IsTrue(phsyChunk.HistogramValues.Count == 256, "Invalid Histogram Values");
        }

        [TestMethod()]
        public void CheckPhysicalDimension2()
        {
            List<PNGBaseChunk> targetFile =
                GetChunksFromFile("cdun2c08.png");
            PhysChunk phsyChunk = ChunkFinder(targetFile, "pHYs").Single() as PhysChunk;
            Assert.IsNotNull(phsyChunk, "No Physical Chunk Found");
            Assert.IsTrue(phsyChunk.PPUXAxis == 1000, "Invalid X Axis");
            Assert.IsTrue(phsyChunk.PPUYAxis == 1000, "Invalid Y Axis");
            Assert.IsTrue(phsyChunk.UnitSpecifier == PhysChunk.enUnitSpecifier.Meter, "Invalid Unit Specifier");
        }

        [TestMethod()]
        public void CheckPhysicalDimension()
        {
            List<PNGBaseChunk> targetFile =
                GetChunksFromFile("cdfn2c08.png");
            PhysChunk phsyChunk = ChunkFinder(targetFile, "pHYs").Single() as PhysChunk;
            Assert.IsNotNull(phsyChunk, "No Physical Chunk Found");
            Assert.IsTrue(phsyChunk.PPUXAxis == 1, "Invalid X Axis");
            Assert.IsTrue(phsyChunk.PPUYAxis == 4, "Invalid Y Axis");
            Assert.IsTrue(phsyChunk.UnitSpecifier == PhysChunk.enUnitSpecifier.Unknown, "Invalid Unit Specifier");
        }

        [TestMethod()]
        public void CheckGamaChunk()
        {
            List<PNGBaseChunk> wholeChunks =
                GetChunksFromFile("g03n0g16.png");
            GamaChunk gamaChunk = ChunkFinder(wholeChunks, "gAMA").Single() as GamaChunk;
            Assert.IsNotNull(gamaChunk, "No Gama Chunk Found In File");
            Assert.IsTrue(gamaChunk.GamaCalculatedValue == 0.35f, "Invalid Gama Value Calculation");
            IHDRChunk headerChunk = ChunkFinder(wholeChunks, "IHDR").Single()
                                    as IHDRChunk;
            Assert.IsNotNull(headerChunk, "Not Missing Header Type");
            Assert.IsTrue(headerChunk.ColorType == IHDRChunk.ColorEnumType.GrayScale, "Invalid Color Type");
        }
        [TestMethod()]
        public void CheckDateTimeData()
        {
            var timeChunks = ChunkFinder(GetChunksFromFile("cm0n0g04.png"), "tIME");
            Assert.IsTrue(timeChunks.Count() > 0, "No ZText Chunk Found In File");
            foreach (var timeChunk in timeChunks)
            {
                System.Diagnostics.Debug.WriteLine(timeChunk.ToString());
                //01-jan-2000 12:34:56
                DateTime targetTime = new DateTime(2000, 1, 1, 12, 34, 56);
                Assert.IsTrue(((TimeChunk)timeChunk).CreationDate == targetTime, "Invalid Time Parsed");
            }
        }

        [TestMethod()]
        public void CheckCompressedTextualData()
        {
            var textChunks = ChunkFinder(GetChunksFromFile("ctzn0g04.png"), "zTXt");
            Assert.IsTrue(textChunks.Count() > 0, "No ZText Chunk Found In File");
            foreach (var textChunk in textChunks)
            {
                System.Diagnostics.Debug.WriteLine(textChunk.ToString());
            }
        }

        [TestMethod()]
        [ExpectedException(typeof(org.webguvenligi.NSecureImageLib.GraphicFileFormats.PNG.Exceptions.IDATException))]
        public void CheckMissingIDATChunk()
        {
            GetChunksFromFile("x00n0g01.png");
        }

    }
}